#ifndef _PIECEWISE_FUNC_H_
#define _PIECEWISE_FUNC_H_

#include <vector>
#include <limits>
#include <iostream>
#include <cassert>

#include "error_info.h"

namespace Nesting
{
	/*
	** piecewise linear/quadratic function to express area
	*/
	class Quad_piecewise_func  
	{
		friend void add(const Quad_piecewise_func& f0, const Quad_piecewise_func& f1, Quad_piecewise_func& sum);

	public:
		struct Coeff
		{
			double a;
			double b;
			double c;

			Coeff() { a = 0.0; b = 0.0; c = 0.0; }
			Coeff(double _a, double _b, double _c) : a(_a), b(_b), c(_c) {	}

			Coeff& operator+=(const Coeff& other)
			{
				a += other.a;
				b += other.b;
				c += other.c;
				return *this;
			}
			Coeff& operator -= (const Coeff& other)
			{
				a -= other.a;
				b -= other.b;
				c -= other.c;
				return *this;
			}

			inline double value_at(double x) const 
			{
				return a * x * x + b * x + c;
			}
		};


	public:
		Quad_piecewise_func() { open = false; }

		double min(double& argmin) const ;
		// find the optimal between l and r
		double min(double l, double r, double &argmin) const; 

		inline unsigned int nb_pieces() const { return coefficients.size(); }

		bool constant_zero() const;
		double value_at(double x) const;
		void begin_insert();
		//void end_insert(double end_breakpoint);
		void end_insert();
		void insert_piece(double start_point, const Coeff& c) ;
		void insert_piece(double start_point, double a, double b, double c);

		void pop_back() ; //delete the last piece
		// debug
		void print();

	private:
		// return the min and argmin of the idx piece
		inline double piece_min(unsigned int idx, double& argmin) const;

	private:
		std::vector<double> breakpoints; // break points of piecewise functions
		std::vector<Coeff> coefficients;

		bool open;
	};

	void add(const Quad_piecewise_func& f0, const Quad_piecewise_func& f1, Quad_piecewise_func& sum);
}
#endif